#include "common_impl.h"
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <poll.h>
#include "dsm_list.h"
#include "dsm_list.c"



/* variables globales */
#define MAXBUF 1024
#define BACKLOG 1024

/* un tableau gerant les infos d'identification */
/* des processus dsm */

dsm_proc_t *proc_array = NULL;

/* le nombre de processus effectivement crees */
volatile int num_procs_creat = 0;

typedef int pipe_t[2];

void usage(void)
{
	fprintf(stdout,"Usage : dsmexec machine_file executable arg1 arg2 ...\n");
	fflush(stdout);
	exit(EXIT_FAILURE);
}

void sigchld_handler(int sig)
{
	/* on traite les fils qui se terminent */
	/* pour eviter les zombies */

	//waitpid
}
/* fonctions de lecture et d'écriture de ligne */



int main(int argc, char *argv[])
{
	int num_procs = 0;
	pid_t pid;
	int i;
	char nom_machine[100][100];// tableau de stockage des noms des machines

	char  *  file_name=argv[1];
	char  tmp[40];
	FILE* file = NULL;

	int curseur_nom = 0;

	// Variables pour la socket
	int s_ecoute; // socket d'écoute
	int s_conn; // socket de connexion
	int port; // numéro du port
	struct sockaddr_in servaddr; // socket addresse structure
	int size_servaddr=sizeof(servaddr);
	char buffer[MAXBUF]; //character buffer
	//char *endptr; // for strtol()

	int optval=1;

	int k=0;

	if (argc < 3){
		usage();
	} else {

		/* Mise en place d'un traitant pour recuperer les fils zombies*/
		/* XXX.sa_handler = sigchld_handler; */

		/* lecture du fichier de machines */

		printf("\n\n Lancement Phase 1\n\n");

		file = fopen(file_name, "r");

		/* 1- on recupere le nombre de processus a lancer */ /* = nombre de lignes du fichier machine_file.txt */
		/* 2- on recupere les noms des machines : le nom de */
		/* la machine est un des elements d'identification */
		do {
			i=fgetc(file);
			if (i=='\n'||i==EOF) {
				num_procs++;
				nom_machine[num_procs][curseur_nom]='\0';
				curseur_nom = 0;
			}
			else {
				/* on stocke les noms des machines dans le tableau nom_machine */
				nom_machine[num_procs][curseur_nom] = (char) i; //on cast c car c int et on veut un char
				curseur_nom++;
			}
		}
		while (i != EOF);

		/* si le fichier est vide, num_procs=1 car EOF, on remet num_procs à 0 */
		if (num_procs == 1 && nom_machine[0][0] == '\0') {
			num_procs = 0;
		}

		printf("\n\n%d processus à créer\n", num_procs);

		for (i=0; i < num_procs; i++) {
			printf("nom machine %d : %s\n", i, nom_machine[i]);

		}

		fclose(file);
	}

	/* creation de la socket d'ecoute */


	if ( (s_ecoute = socket(AF_INET,SOCK_STREAM,0)) < 0 ){
		fprintf(stderr, "ECHOSERV :Error creating listening socket.\n");

		exit( EXIT_FAILURE );
	}

	/* Set all bytes in socket address structure to
                     zero, and fill in the relevant data members */

	memset(&servaddr, 0, sizeof (servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = 0;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	setsockopt(s_ecoute,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval));

	/*  Bind our socket address to the listening socket*/

	if (bind( s_ecoute,(struct sockaddr *) &servaddr,sizeof(servaddr)) < 0 ){
		fprintf(stderr, "ECHOSERV :Error calling binding().\n");
		exit( EXIT_FAILURE );
	}
	/* On assigne un port aléatoire*/

	struct sockaddr_in sock_info;
	socklen_t size = sizeof(sock_info);
	getsockname(s_ecoute, (struct sockaddr *) &sock_info, &size);
	fprintf(stdout,"port : %d\n\n", ntohs(sock_info.sin_port));
	port=ntohs(sock_info.sin_port);




	/* + ecoute effective */

	if (listen( s_ecoute, BACKLOG) < 0 ){
		fprintf(stderr, "ECHOSERV :Error calling listen().\n");
		exit( EXIT_FAILURE );
	}


	/* creation des fils */

	//typedef int pipe_t[2];
	pipe_t stdout_fils[num_procs];
	pipe_t stderr_fils[num_procs];

//			stdout_fils=/*(pipe_t*)*/malloc(sizeof(pipe_t));
//			stderr_fils=/*(pipe_t*)*/malloc(sizeof(pipe_t));

	// Initialisation machine

	t_machine_list list =new_t_machine_list();

	for (i=0; i<num_procs;i++){

		int pid2=getpid();
		add_t_machine_list(list,nom_machine[i],port,pid2);

	}

	list_display(list);

	for(i = 0; i < num_procs ; i++) {

		/* creation du tube pour rediriger stdout */
		pipe(stdout_fils[i]);

		/* creation du tube pour rediriger stderr */
		pipe(stderr_fils[i]);

		pid = fork();
		if(pid == -1) ERROR_EXIT("fork");

		if (pid == 0) { /* fils */


			// empeche la lecture sur tous les pipes de ses freres
			for (k=0; k <= i ; k++){
				close(stdout_fils[k][0]);
				close(stderr_fils[k][0]);
			}

			/* redirection stderr */

			close(STDERR_FILENO);
			dup(stderr_fils[i][1]);
			close(stderr_fils[i][1]);

			/* redirection stdout */

			close(STDOUT_FILENO);
			dup(stdout_fils[i][1]);
			close(stdout_fils[i][1]);


			/* Creation du tableau d'arguments pour le ssh */
			char port_send[1024];
			sprintf(port_send,"%d",port);
			char pid_temp[1024];
			sprintf(pid_temp,"%d",get_pid(find_machine_name(list,nom_machine[i])));

			char** newarg=malloc(7*sizeof(char*));
			newarg[0]="ssh";
			newarg[1]=nom_machine[i];// Nom de machine avec laquelle on veut se connecter
			newarg[2]="./dsmwrap"; // on execute dsmwrap
			newarg[3]=port_send; // port
			newarg[4]=pid_temp;// pid envoyé
			newarg[5]=nom_machine[i];// nom  de la machine transmis
			newarg[6]= argv[2]; // Nom de l'executable qu'on cherche à lancer (ici truc)
			newarg[7]=NULL;

			/* jump to new prog : */
			execvp("ssh",newarg);
			perror("execvp");


		} else  if(pid > 0) { /* pere */

			/* fermeture des extremites des tubes non utiles */
			// ferme descripteur en ecriture

			close(stderr_fils[i][1]);
			close(stdout_fils[i][1]);

			fprintf(stdout,"pid fils : %i\n",pid);

			fflush(stdout);

			//read(stdout_fils[i][0], buffer,sizeof(buffer));
			//fprintf(stdout,"read : %s\n",buffer);

			fflush(stdout);

			num_procs_creat++;
		}
	}


	for(i = 0; i < num_procs ; i++){

		/* on accepte les connexions des processus dsm */


		printf("avant accept\n");

		if ((s_conn = accept(s_ecoute, (struct sockaddr *)&servaddr, (socklen_t*)&size_servaddr)) == -1 ){
			perror("Error accept");
			exit(EXIT_FAILURE);
		}

		printf("accept OK\n");

		/*  On recupere le nom de la machine distante */

		/*  On recupere le nom de la machine distante */
		/* 1- d'abord la taille de la chaine */

		read(s_conn, buffer, sizeof(buffer));
		int taille=atoi(buffer);
		printf("taille machine: %d\n", taille);

		/* 2- puis la chaine elle-meme */
		read(s_conn, buffer, taille);
		char * nom=strdup(buffer);
		printf("nom : %s\n", nom);

		// On considere que le port et le pid ont 5 chiffres
		/* On recupere le pid du processus distant  */
		read(s_conn, buffer, sizeof(char)*5);
		int pid_received=atoi(buffer);
		printf(" pid : %d\n", pid_received);

		/* On recupere le numero de port de la socket */
		/* d'ecoute des processus distants */
		read(s_conn, buffer, sizeof(char)*5);
		int num_port=atoi(buffer);
		printf(" num : %d\n", num_port);


		char out[1024];
		read(stdout_fils[i][0],out,sizeof(out));
		printf("[Proc %d : %s : stdout] %s\n",i, nom_machine[i],out);

		char err[1024];
		bzero(err,sizeof(err));

		read(stderr_fils[i][0],err,sizeof(err));
		printf("[Proc %d : %s : stderr] %s\n",i, nom_machine[i],err);

	}


	/* envoi du nombre de processus aux processus dsm*/

	/* envoi des rangs aux processus dsm */

	/* envoi des infos de connexion aux processus */

	/* gestion des E/S : on recupere les caracteres */
	/* sur les tubes de redirection de stdout/stderr */
	/* while(1)
	         {
	            je recupere les infos sur les tubes de redirection
	            jusqu'à ce qu'ils soient inactifs (ie fermes par les
	            processus dsm ecrivains de l'autre cote ...)

	         };
	 */

	/* on attend les processus fils */

	/* on ferme les descripteurs proprement */

	// faire free


	/* on ferme la socket d'ecoute */

	//	if ( close(s_ecoute) < 0 ) {
	//		fprintf(stderr,"ECHOSERV : Error calling close()\n");
	//		exit(EXIT_FAILURE);
	//	}
	//	printf("end\n");
	//
	//	exit(EXIT_SUCCESS);
}

